import { constantRoutes } from "@/router";
import ParentView from "@/components/ParentView";
import Util from "@/libs/framework/util";
import request from "@/utils/request";

const permission = {
  state: {
    routes: [],
    addRoutes: [],
    defaultRoutes: [],
    topbarRouters: [],
    sidebarRouters: [],
    leavesRouterPaths: [],
    notCacheRouterNames: [],
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes;
      state.routes = constantRoutes.concat(routes);
    },
    SET_DEFAULT_ROUTES: (state, routes) => {
      state.defaultRoutes = constantRoutes.concat(routes);
    },
    SET_TOPBAR_ROUTES: (state, routes) => {
      state.topbarRouters = routes;
    },
    SET_SIDEBAR_ROUTERS: (state, routes) => {
      state.sidebarRouters = routes;
    },
    SET_LEAVES_ROUTER_PATHS: (state, routes) => {
      state.leavesRouterPaths = routes;
    },
    SET_NOT_CACHE_ROUTER_NAMES: (state, routes) => {
      state.notCacheRouterNames = routes;
    },
  },
  actions: {
    // 生成路由
    GenerateRoutes({ commit }) {
      return new Promise((resolve) => {
        // 向后端请求路由数据
        request({
          url: "/account/getUserRouters",
          method: "post",
        }).then((res) => {
          const menus = res.parameters.menus;

          const rs = buildRoutesFilter(menus);
          /**
           * SIDEBAR_ROUTERS 与 ROUTES 不能分两次构建，不然会导致buildRuoute name、path不一致.
           * 在使用router path 与 SIDEBAR_ROUTERS 会出现匹对不上问题，从而导致路由跳转404问题.
           * 故，这边构建 ROUTES 需在 SIDEBAR_ROUTERS 基础上构建.
           */
          const rewriteRoutes = buildRewriteRoutesFilter(rs);

          const routes = constantRoutes.concat(rs);
          const notCacheRouterNames = buildNotCacheRouterNames(routes);
          const leavesRouterPaths = buildLeavesRouterPaths(routes);
          rewriteRoutes.push({
            path: "*",
            redirect: "/404",
            hidden: true,
          });
          // 不支持二级以上菜单缓存,需要将二级以上的路由拍平
          commit("SET_ROUTES", rewriteRoutes);
          commit("SET_SIDEBAR_ROUTERS", routes);
          commit("SET_DEFAULT_ROUTES", rs);
          commit("SET_TOPBAR_ROUTES", routes);
          commit("SET_LEAVES_ROUTER_PATHS", leavesRouterPaths);
          commit("SET_NOT_CACHE_ROUTER_NAMES", notCacheRouterNames);
          resolve(rewriteRoutes);
        });
      });
    },
  },
};

/**
 * 在 SIDEBAR_ROUTERS 路由基础上构建路由。
 * 注：keep-alive 默认支持缓存是两级，所以需要进行扁平化处理，将多级路由转成二级路由。
 * @param {*} routes
 */
function buildRewriteRoutesFilter(routes) {
  const rewriteRoutesutes = [];
  routes.forEach((m) => {
    const r = Object.assign({}, m);
    if (m.children && m.children.length) {
      let childrenRoutes = [];
      childrenRoutes = filterRewriteRoutesChildren(m.children);
      r.children = childrenRoutes;
    }
    rewriteRoutesutes.push(r);
  });
  return rewriteRoutesutes;
}

/**
 * 构建 RewriteRoutes 子节点
 * @param {*} childrenRoutes
 */
function filterRewriteRoutesChildren(childrenRoutes) {
  let children = [];
  childrenRoutes.forEach((el, index) => {
    if (el.children && el.children.length) {
      el.children.forEach((c) => {
        if (c.children && c.children.length) {
          if (!isNestedMenus(c.children)) {
            const r = Object.assign({}, c);
            r.children = [];
            children.push(r);
          }
          children = children.concat(filterRewriteRoutesChildren(c.children));
        } else {
          children.push(c);
        }
      });
    }
    const r = Object.assign({}, el);
    r.children = [];
    children = children.concat(r);
  });
  return children;
}

/**
 *
 * 原项目是根据tagsView进行构建缓存的路由。
 * 但有些项目是不开启tagsView，所以需要自行构建不缓存的路由名字。
 *
 * @param {*} routes
 */
function buildNotCacheRouterNames(routes) {
  const notCacheRouterNames = [];
  function recursiveFun(routes) {
    routes.forEach((item) => {
      if (item.meta && item.meta.noCache) {
        notCacheRouterNames.push(item.name);
      }
      if (
        item.children &&
        Array.isArray(item.children) &&
        item.children.length > 0
      ) {
        recursiveFun(item.children);
      }
    });
  }
  recursiveFun(routes);
  return notCacheRouterNames;
}

function buildLeavesRouterPaths(routes, excludePaths = ["*", "/redirect"]) {
  const leavesRouterPaths = [];
  function recursiveFun(routes) {
    if (Array.isArray(routes) && routes.length > 0) {
      routes.forEach((item) => {
        if (!excludePaths.includes(item.path)) {
          if (!item.children && !leavesRouterPaths.includes(item.path)) {
            leavesRouterPaths.push(item.path);
          } else {
            recursiveFun(item.children);
          }
        }
      });
    }
  }
  recursiveFun(routes);
  return leavesRouterPaths;
}

function buildRoutesFilter(menus) {
  return buildRoutes(
    menus.filter((m) => {
      return !m.parentId && m.isEnabled && !m.isDeleted;
    })
  );
}

function buildRoutes(menus) {
  const routes = [];
  menus.forEach((m) => {
    if (m.menuType === "menu" && m.isEnabled && !m.isDeleted) {
      const r = buildRuoute(m);
      if (m.children && m.children.length) {
        if (Array.isArray(r.children)) {
          r.children.push(...buildRoutes(m.children));
        } else {
          r.children = buildRoutes(m.children);
        }
      }
      routes.push(r);
    }
  });
  return routes;
}

function buildRuoute(m) {
  const navigateUrl = m.navigateUrl ? m.navigateUrl.trim() : m.navigateUrl;

  const r = {
    path: Util.padPrefix(m.code, "/") || navigateUrl || "/" + Math.uuidFast(),
    name:
      Util.padPrefix(m.code, "/") ||
      getComponentName(navigateUrl) ||
      "/" + Math.uuidFast(),
    hidden: !m.isVisible,
    alwaysShow:
      m.children &&
      m.children.filter(
        (item) => item.isEnabled && !item.isDeleted && item.isVisible
      ).length > 0,
    meta: {
      icon: m.icon || "system",
      title: m.name,
      noCache: !m.isCache,
      keepalive: m.isCache,
    },
  };

  if (!m.parentId && !navigateUrl) {
    // 最外一层菜单，不可点击跳转
    r.component = loadLayout(m.layout);
  } else if (m.children && m.children.length > 0 && isNestedMenus(m.children)) {
    r.component = m.parentId ? ParentView : loadLayout(m.layout);
  } else if (navigateUrl) {
    let vpath = navigateUrl;
    if (navigateUrl.indexOf("?") > -1) {
      vpath = navigateUrl.substring(0, navigateUrl.indexOf("?"));
      r.path = r.name = Util.padPrefix(m.code, "/") || vpath;
    }
    if (navigateUrl.startsWith("/smartform/hub/") && m.target !== "_blank") {
      r.path = r.name = Util.padPrefix(m.code, "/") || vpath;
      vpath = "/smartform/smartForm/render";
    }
    if (navigateUrl.startsWith("/smartform/view/") && m.target !== "_blank") {
      r.path = r.name = Util.padPrefix(m.code, "/") || vpath;
      vpath = "/smartform/smartForm/viewRender";
    }
    if (
      navigateUrl.startsWith("/smartform/workflow/") &&
      m.target !== "_blank"
    ) {
      r.path = r.name = Util.padPrefix(m.code, "/") || vpath;
      vpath = "/smartform/smartForm/workflow";
    }
    r.component = loadView(vpath);

    if (navigateUrl.indexOf("?") > -1) {
      r.query = Util.getUrlAllParams(navigateUrl);
    }

    r.meta.page = navigateUrl;
    r.meta.newTab = m.target === "_blank";

    if (!m.parentId && m.target !== "_blank") {
      // 有跳转链接的一级菜单，且在本页打开的
      r.children = [Util.extend({}, r)];
      r.component = loadLayout(m.layout);
      r.path = r.name = Math.uuidFast();
      r.meta = {
        icon: m.icon || "system",
        title: m.name,
      };
    }
  }

  return r;
}

/**
 * navigateUrl结构是/xxx/xxx/xxx，直接使用这种格式，在Component定义name时，会报错，报错信息如下：
 * Invalid component name: "/xxx/xxx/xxx". Component names should conform to valid custom element name in html5 specification.
 *
 * 现将"/xxx/xxx/xxx"格式转为"xxx-xxx-xxx"格式
 * @param {*} navigateUrl
 */
function getComponentName(navigateUrl) {
  const condition =
    typeof navigateUrl === "string" &&
    navigateUrl.trim().length > 0 &&
    navigateUrl.includes("/");
  if (condition) {
    const name = navigateUrl.replaceAll("/", "-");
    if (name.indexOf("-") === 0) {
      return name.slice(1);
    }
    return name;
  }
  return navigateUrl;
}

/**
 * 判断是否为嵌套菜单(子菜单皆为不显示菜单，则该菜单为嵌套菜单，不可点击跳转)
 * @param {*} menus
 */
function isNestedMenus(menus) {
  const visibleMenu = (menus || []).find((item) => item.isVisible);
  return visibleMenu ? true : false;
}

export const loadView = (view) => {
  // 路由懒加载
  view = view.startsWith("/") ? view : `/${view}`;
  return (resolve) => require([`@/views${view}`], resolve);
};

function loadLayout(layoutPath) {
  if (layoutPath) {
    layoutPath = layoutPath.startsWith("/") ? layoutPath : `/${layoutPath}`;
  } else {
    layoutPath = "/index";
  }
  return (resolve) => require([`@/layout${layoutPath}`], resolve);
}

export default permission;
